// 可行，线段树待调试
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int MAXN = 2e4;

// 线段树节点结构体
struct SEG {
  int sum;     // 当前节点的总和
  int left;    // 区间左端点
  int right;   // 区间右端点
  int lazyTag; // 懒惰标记，用于延迟更新
  int count;   // 当前区间内的元素数量
};

// 定义线段树的大小
SEG tree[MAXN << 2 | 10];

// 排序结构体
struct ValueIndexPair {
  int value; // 数值
  int index; // 原始下标
};

// 用于存储输入的数组
ValueIndexPair valueIndexPairs[MAXN + 10];

int a[MAXN + 10], c[MAXN + 10], d[MAXN + 10];
int tot = 0, root = 0;

inline bool cmp(const ValueIndexPair &x, const ValueIndexPair &y) {
  return x.value < y.value;
}

inline void pushup(int node) {
  tree[node].sum =
      tree[node * 2].sum + tree[node * 2 + 1].sum; // 使用索引计算左右子树
  tree[node].count = tree[node * 2].count + tree[node * 2 + 1].count;
}

inline void pushdown(int node) {
  int val = tree[node].lazyTag;
  if (node * 2 < MAXN << 2) { // 确保索引有效
    tree[node * 2].sum += val * tree[node * 2].count;
    tree[node * 2].lazyTag += val;
  }
  if (node * 2 + 1 < MAXN << 2) { // 确保索引有效
    tree[node * 2 + 1].sum += val * tree[node * 2 + 1].count;
    tree[node * 2 + 1].lazyTag += val;
  }
  tree[node].lazyTag = 0;
}

void Insert(int index, int left, int right,
            int &root) { // Renamed 'x' to 'index', 'l' to 'left', 'r' to
                         // 'right' for clarity
  if (!root) {
    root = ++tot;
    tree[root].left = left, tree[root].right = right;
    tree[root].lazyTag = tree[root].sum = 0;
    tree[root].count = 1;
  }
  if (left == right)
    return;
  int mid = (left + right) >> 1; // Added parentheses for clarity
  pushdown(root);
  if (index <= mid)
    Insert(index, left, mid, tree[root].lc); // 这里需要根据新的逻辑调整
  else
    Insert(index, mid + 1, right, tree[root].rc); // 这里需要根据新的逻辑调整
  pushup(root);
}

void update(int l, int r, int s, int val) {
  if (tree[s].left > r || tree[s].right < l)
    return;
  if (l <= tree[s].left && tree[s].right <= r) {
    tree[s].lazyTag += val;
    tree[s].sum += val * tree[s].count;
    return;
  }
  pushdown(s);
  update(l, r, tree[s].lc, val);
  update(l, r, tree[s].rc, val);
  pushup(s);
}

int query(int l, int r, int s) {
  if (tree[s].right < l || tree[s].left > r)
    return 0;
  if (l <= tree[s].left && tree[s].right <= r)
    return tree[s].sum;
  pushdown(s);
  return query(l, r, tree[s].lc) + query(l, r, tree[s].rc);
}

int main() {
  // freopen ("std.in","r",stdin);
  // freopen ("std.out","w",stdout);
  memset(tree, 0, sizeof(tree));
  int n; // 输入的正整数 n
  cin >> n;

  // 读取排列并初始化结构体
  for (int i = 1; i <= n; ++i) {
    cin >> a[i];                     // 读取每个元素
    valueIndexPairs[i].value = a[i]; // 将值存入结构体
    valueIndexPairs[i].index = i;    // 存储原始下标
  }

  sort(valueIndexPairs + 1, valueIndexPairs + n + 1, cmp); // 按值排序

  int ans = 0; // 记录符合条件的三元组数量
  for (int i = 1; i <= n; ++i) {
    c[valueIndexPairs[i].index] = i; // 记录排序后的下标
    d[i] = valueIndexPairs[i].value; // 记录排序后的值
  }

  // 从后向前遍历以查找符合条件的三元组
  for (int i = n; i >= 1; --i) {
    int currentIndex = c[i]; // 当前元素的排序下标
    int upperBound =
        lower_bound(d + 1, d + n + 1, valueIndexPairs[currentIndex].value + 1) -
        d;                             // 找到大于当前值的下界
    ans += query(upperBound, n, root); // 查询符合条件的三元组数量

    // 更新操作
    int lowerBound =
        lower_bound(d + 1, d + n + 1, valueIndexPairs[currentIndex].value) - d -
        1;                            // 找到小于当前值的上界
    update(1, lowerBound, root, 1);   // 更新树
    Insert(currentIndex, 1, n, root); // 插入当前元素
  }

  // 输出结果
  if (tree[0].lazyTag == 0 && tree[0].sum == 0)
    printf("%lld\n", ans); // 输出符合条件的三元组数量
  return 0;
}
